From 1ad93a683b7f00c532a522dcf7a0107e4cd28ee5 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 20 Feb 2006 01:36:50 +0000 Subject: [PATCH] Support input shapes: (#331070) 2006-02-19 Matthias Clasen Support input shapes: (#331070) * gdk/gdk.symbols: * gdk/gdkdisplay.h: * gdk/gdkwindow.h: * gdk/x11/gdkdisplay-x11.c (gdk_display_supports_shapes) (gdk_display_supports_input_shapes): Functions to determine if a display supports shaped windows or input shapes. * gdk/x11/gdkwindow-x11.c (gdk_window_input_shape_combine_region): (gdk_window_input_shape_combine_mask): (gdk_window_set_child_input_shapes): (gdk_window_merge_child_input_shapes): Input shape versions of the window shape API. * gtk/gtk.symbols: * gtk/gtkwidget.h: * gtk/gtkwidget.c (gtk_widget_input_shape_combine_mask): New function to set an input shape on a widget. --- ChangeLog | 22 +++ ChangeLog.pre-2-10 | 22 +++ gdk/gdk.symbols | 6 + gdk/gdkdisplay.h | 3 + gdk/gdkwindow.h | 12 ++ gdk/x11/gdkdisplay-x11.c | 58 +++++++- gdk/x11/gdkwindow-x11.c | 280 +++++++++++++++++++++++++++++---------- gtk/gtk.symbols | 1 + gtk/gtkwidget.c | 86 +++++++++--- gtk/gtkwidget.h | 4 + 10 files changed, 406 insertions(+), 88 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3656994973..798bc43e93 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2006-02-19 Matthias Clasen + + Support input shapes: (#331070) + + * gdk/gdk.symbols: + * gdk/gdkdisplay.h: + * gdk/gdkwindow.h: + * gdk/x11/gdkdisplay-x11.c (gdk_display_supports_shapes) + (gdk_display_supports_input_shapes): Functions to determine + if a display supports shaped windows or input shapes. + + * gdk/x11/gdkwindow-x11.c (gdk_window_input_shape_combine_region): + (gdk_window_input_shape_combine_mask): + (gdk_window_set_child_input_shapes): + (gdk_window_merge_child_input_shapes): Input shape versions + of the window shape API. + + * gtk/gtk.symbols: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c (gtk_widget_input_shape_combine_mask): + New function to set an input shape on a widget. + 2006-02-19 Matthias Clasen * gtk/gtklinkbutton.c (gtk_link_button_class_init): Fix diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 3656994973..798bc43e93 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,25 @@ +2006-02-19 Matthias Clasen + + Support input shapes: (#331070) + + * gdk/gdk.symbols: + * gdk/gdkdisplay.h: + * gdk/gdkwindow.h: + * gdk/x11/gdkdisplay-x11.c (gdk_display_supports_shapes) + (gdk_display_supports_input_shapes): Functions to determine + if a display supports shaped windows or input shapes. + + * gdk/x11/gdkwindow-x11.c (gdk_window_input_shape_combine_region): + (gdk_window_input_shape_combine_mask): + (gdk_window_set_child_input_shapes): + (gdk_window_merge_child_input_shapes): Input shape versions + of the window shape API. + + * gtk/gtk.symbols: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c (gtk_widget_input_shape_combine_mask): + New function to set an input shape on a widget. + 2006-02-19 Matthias Clasen * gtk/gtklinkbutton.c (gtk_link_button_class_init): Fix diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols index b9485e3584..c628388e08 100644 --- a/gdk/gdk.symbols +++ b/gdk/gdk.symbols @@ -460,6 +460,8 @@ gdk_display_request_selection_notification gdk_display_store_clipboard gdk_display_supports_clipboard_persistence gdk_display_supports_selection_notification +gdk_display_supports_shapes +gdk_display_supports_input_shapes #endif #endif @@ -728,6 +730,8 @@ gdk_window_get_events gdk_window_set_events gdk_window_shape_combine_mask gdk_window_shape_combine_region +gdk_window_input_shape_combine_mask +gdk_window_input_shape_combine_region gdk_window_set_override_redirect gdk_window_set_accept_focus gdk_window_set_focus_on_map @@ -751,6 +755,8 @@ gdk_window_set_decorations gdk_window_set_functions gdk_window_set_child_shapes gdk_window_merge_child_shapes +gdk_window_set_child_input_shapes +gdk_window_merge_child_input_shapes gdk_window_set_static_gravities gdk_window_begin_move_drag gdk_window_begin_resize_drag diff --git a/gdk/gdkdisplay.h b/gdk/gdkdisplay.h index d00fa5b5b2..c627a08581 100644 --- a/gdk/gdkdisplay.h +++ b/gdk/gdkdisplay.h @@ -179,6 +179,9 @@ void gdk_display_store_clipboard (GdkDisplay *display, GdkAtom *targets, gint n_targets); +gboolean gdk_display_supports_shapes (GdkDisplay *display); +gboolean gdk_display_supports_input_shapes (GdkDisplay *display); + G_END_DECLS #endif /* __GDK_DISPLAY_H__ */ diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h index e7570ab78c..4ff4847e16 100644 --- a/gdk/gdkwindow.h +++ b/gdk/gdkwindow.h @@ -396,6 +396,18 @@ void gdk_window_set_child_shapes (GdkWindow *window); */ void gdk_window_merge_child_shapes (GdkWindow *window); +void gdk_window_input_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, + gint y); +void gdk_window_input_shape_combine_region (GdkWindow *window, + GdkRegion *shape_region, + gint offset_x, + gint offset_y); +void gdk_window_set_child_input_shapes (GdkWindow *window); +void gdk_window_merge_child_input_shapes (GdkWindow *window); + + /* * Check if a window has been shown, and whether all its * parents up to a toplevel have been shown, respectively. diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index 263d37ab5c..6821ca8480 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -50,6 +50,11 @@ #include #endif +#ifdef HAVE_SHAPE_EXT +#include +#endif + + static void gdk_display_x11_class_init (GdkDisplayX11Class *class); static void gdk_display_x11_dispose (GObject *object); static void gdk_display_x11_finalize (GObject *object); @@ -158,8 +163,9 @@ gdk_display_open (const gchar *display_name) XClassHint *class_hint; gulong pid; gint i; -#ifdef HAVE_XFIXES +#if defined(HAVE_XFIXES) || defined(HAVE_SHAPE_EXT) gint ignore; + gint maj, min; #endif xdisplay = XOpenDisplay (display_name); @@ -224,7 +230,20 @@ gdk_display_open (const gchar *display_name) } else #endif - display_x11->have_xfixes = FALSE; + display_x11->have_xfixes = FALSE; + + display_x11->have_shapes = FALSE; + display_x11->have_input_shapes = FALSE; +#ifdef HAVE_SHAPE_EXT + if (XShapeQueryExtension (GDK_DISPLAY_XDISPLAY (display), &ignore, &ignore)) + { + display_x11->have_shapes = TRUE; +#ifdef ShapeInput + if (XShapeQueryVersion (GDK_DISPLAY_XDISPLAY (display), &maj, &min)) + display_x11->have_input_shapes = (maj == 1 && min >= 1); +#endif + } +#endif if (_gdk_synchronize) XSynchronize (display_x11->xdisplay, True); @@ -1237,5 +1256,40 @@ gdk_x11_display_get_user_time (GdkDisplay *display) return GDK_DISPLAY_X11 (display)->user_time; } +/** + * gdk_display_supports_shapes: + * @display: a #GdkDisplay + * + * Returns %TRUE if gdk_window_shape_combine_mask() can + * be used to create shaped windows on @display. + * + * Returns: %TRUE if shaped windows are supported + * + * Since: 2.10 + */ +gboolean +gdk_display_supports_shapes (GdkDisplay *display) +{ + return GDK_DISPLAY_X11 (display)->have_shapes; +} + +/** + * gdk_display_supports_input_shapes: + * @display: a #GdkDisplay + * + * Returns %TRUE if gdk_window_input_shape_combine_mask() can + * be used to modify the input shape of windows on @display. + * + * Returns: %TRUE if windows with modified input shape are supported + * + * Since: 2.10 + */ +gboolean +gdk_display_supports_input_shapes (GdkDisplay *display) +{ + return GDK_DISPLAY_X11 (display)->have_input_shapes; +} + + #define __GDK_DISPLAY_X11_C__ #include "gdkaliasdef.c" diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c index 374a345cf8..59ffd53122 100644 --- a/gdk/x11/gdkwindow-x11.c +++ b/gdk/x11/gdkwindow-x11.c @@ -83,7 +83,6 @@ const int _gdk_nenvent_masks = sizeof (_gdk_event_mask_table) / sizeof (int); /* Forward declarations */ static void gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on); -static gboolean gdk_window_have_shape_ext (GdkDisplay *display); static gboolean gdk_window_icon_name_set (GdkWindow *window); static void gdk_window_add_colormap_windows (GdkWindow *window); static void set_wm_name (GdkDisplay *display, @@ -3686,19 +3685,6 @@ gdk_window_add_colormap_windows (GdkWindow *window) XFree (old_windows); } -static gboolean -gdk_window_have_shape_ext (GdkDisplay *display) -{ -#ifdef HAVE_SHAPE_EXT - int ignore; - - return XShapeQueryExtension (GDK_DISPLAY_XDISPLAY (display), - &ignore, &ignore); -#else - return 0; -#endif -} - #define WARN_SHAPE_TOO_BIG() g_warning ("GdkWindow is too large to allow the use of shape masks or shape regions.") /* @@ -3706,34 +3692,12 @@ gdk_window_have_shape_ext (GdkDisplay *display) * If not available, shaped windows will look * ugly, but programs still work. Stefan Wille */ -/** - * gdk_window_shape_combine_mask: - * @window: a #GdkWindow - * @mask: shape mask - * @x: X position of shape mask with respect to @window - * @y: Y position of shape mask with respect to @window - * - * Applies a shape mask to @window. Pixels in @window corresponding to - * set bits in the @mask will be visible; pixels in @window - * corresponding to unset bits in the @mask will be transparent. This - * gives a non-rectangular window. - * - * If @mask is %NULL, the shape mask will be unset, and the @x/@y - * parameters are not used. - * - * On the X11 platform, this uses an X server extension which is - * widely available on most common platforms, but not available on - * very old X servers, and occasionally the implementation will be - * buggy. On servers without the shape extension, this function - * will do nothing. - * - * This function works on both toplevel and child windows. - * - **/ -void -gdk_window_shape_combine_mask (GdkWindow *window, - GdkBitmap *mask, - gint x, gint y) +static void +do_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, + gint y, + gint shape) { GdkWindowObject *private = (GdkWindowObject *)window; Pixmap pixmap; @@ -3753,13 +3717,15 @@ gdk_window_shape_combine_mask (GdkWindow *window, return; } - if (gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window))) + if (shape == ShapeBounding + ? gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)) + : gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window))) { if (mask) { pixmap = GDK_PIXMAP_XID (mask); - private->shaped = TRUE; + private->shaped = (shape == ShapeBounding); } else { @@ -3772,7 +3738,7 @@ gdk_window_shape_combine_mask (GdkWindow *window, XShapeCombineMask (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), - ShapeBounding, + shape, x, y, pixmap, ShapeSet); @@ -3781,20 +3747,20 @@ gdk_window_shape_combine_mask (GdkWindow *window, } /** - * gdk_window_shape_combine_region: + * gdk_window_shape_combine_mask: * @window: a #GdkWindow - * @shape_region: region of window to be non-transparent - * @offset_x: X position of @shape_region in @window coordinates - * @offset_y: Y position of @shape_region in @window coordinates + * @mask: shape mask + * @x: X position of shape mask with respect to @window + * @y: Y position of shape mask with respect to @window * - * Makes pixels in @window outside @shape_region be transparent, - * so that the window may be nonrectangular. See also - * gdk_window_shape_combine_mask() to use a bitmap as the mask. + * Applies a shape mask to @window. Pixels in @window corresponding to + * set bits in the @mask will be visible; pixels in @window + * corresponding to unset bits in the @mask will be transparent. This + * gives a non-rectangular window. + * + * If @mask is %NULL, the shape mask will be unset, and the @x/@y + * parameters are not used. * - * If @shape_region is %NULL, the shape will be unset, so the whole - * window will be opaque again. @offset_x and @offset_y are ignored - * if @shape_region is %NULL. - * * On the X11 platform, this uses an X server extension which is * widely available on most common platforms, but not available on * very old X servers, and occasionally the implementation will be @@ -3805,11 +3771,56 @@ gdk_window_shape_combine_mask (GdkWindow *window, * **/ void -gdk_window_shape_combine_region (GdkWindow *window, - GdkRegion *shape_region, - gint offset_x, - gint offset_y) -{ +gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, + gint y) +{ + do_shape_combine_mask (window, mask, x, y, ShapeBounding); +} + +/** + * gdk_window_input_shape_combine_mask: + * @window: a #GdkWindow + * @mask: shape mask + * @x: X position of shape mask with respect to @window + * @y: Y position of shape mask with respect to @window + * + * Like gdk_window_shape_combine_mask(), but the shape applies + * only to event handling. Mouse events which happen while + * the pointer position corresponds to an unset bit in the + * mask will be passed on the window below @window. + * + * An input shape is typically used with RGBA windows. + * The alpha channel of the window defines which pixels are + * invisible and allows for nicely antialiased borders, + * and the input shape controls where the window is + * "clickable". + * + * On the X11 platform, this requires version 1.1 of the + * shape extension. + * + * Since: 2.10 + */ +void +gdk_window_input_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, + gint y) +{ +#ifdef ShapeInput + do_shape_combine_mask (window, mask, x, y, ShapeInput); +#endif +} + + +static void +do_shape_combine_region (GdkWindow *window, + GdkRegion *shape_region, + gint offset_x, + gint offset_y, + gint shape) +{ GdkWindowObject *private = (GdkWindowObject *)window; gint xoffset, yoffset; @@ -3834,12 +3845,14 @@ gdk_window_shape_combine_region (GdkWindow *window, return; } - if (gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window))) + if (shape == ShapeBounding + ? gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)) + : gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window))) { gint n_rects = 0; XRectangle *xrects = NULL; - private->shaped = TRUE; + private->shaped = shape == ShapeBounding; _gdk_region_get_xrectangles (shape_region, 0, 0, @@ -3847,7 +3860,7 @@ gdk_window_shape_combine_region (GdkWindow *window, XShapeCombineRectangles (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), - ShapeBounding, + shape, offset_x, offset_y, xrects, n_rects, ShapeSet, @@ -3858,6 +3871,73 @@ gdk_window_shape_combine_region (GdkWindow *window, #endif /* HAVE_SHAPE_EXT */ } +/** + * gdk_window_shape_combine_region: + * @window: a #GdkWindow + * @shape_region: region of window to be non-transparent + * @offset_x: X position of @shape_region in @window coordinates + * @offset_y: Y position of @shape_region in @window coordinates + * + * Makes pixels in @window outside @shape_region be transparent, + * so that the window may be nonrectangular. See also + * gdk_window_shape_combine_mask() to use a bitmap as the mask. + * + * If @shape_region is %NULL, the shape will be unset, so the whole + * window will be opaque again. @offset_x and @offset_y are ignored + * if @shape_region is %NULL. + * + * On the X11 platform, this uses an X server extension which is + * widely available on most common platforms, but not available on + * very old X servers, and occasionally the implementation will be + * buggy. On servers without the shape extension, this function + * will do nothing. + * + * This function works on both toplevel and child windows. + * + **/ +void +gdk_window_shape_combine_region (GdkWindow *window, + GdkRegion *shape_region, + gint offset_x, + gint offset_y) +{ + do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeBounding); +} + +/** + * gdk_window_input_shape_combine_region: + * @window: a #GdkWindow + * @shape_region: region of window to be non-transparent + * @offset_x: X position of @shape_region in @window coordinates + * @offset_y: Y position of @shape_region in @window coordinates + * + * Like gdk_window_shape_combine_region(), but the shape applies + * only to event handling. Mouse events which happen while + * the pointer position corresponds to an unset bit in the + * mask will be passed on the window below @window. + * + * An input shape is typically used with RGBA windows. + * The alpha channel of the window defines which pixels are + * invisible and allows for nicely antialiased borders, + * and the input shape controls where the window is + * "clickable". + * + * On the X11 platform, this requires version 1.1 of the + * shape extension. + * + * Since: 2.10 + */ +void +gdk_window_input_shape_combine_region (GdkWindow *window, + GdkRegion *shape_region, + gint offset_x, + gint offset_y) +{ +#ifdef ShapeInput + do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeInput); +#endif +} + /** * gdk_window_set_override_redirect: @@ -5120,7 +5200,8 @@ gdk_add_rectangles (Display *disp, static void gdk_propagate_shapes (Display *disp, Window win, - gboolean merge) + gboolean merge, + int shape) { Window rt, par, *list = NULL; gint i, j, num = 0, num_rects = 0; @@ -5225,7 +5306,7 @@ gdk_propagate_shapes (Display *disp, /* set the rects as the shape mask */ if (rects) { - XShapeCombineRectangles (disp, win, ShapeBounding, 0, 0, rects, num_rects, + XShapeCombineRectangles (disp, win, shape, 0, 0, rects, num_rects, ShapeSet, YXSorted); g_free (rects); } @@ -5261,11 +5342,12 @@ gdk_window_set_child_shapes (GdkWindow *window) { g_return_if_fail (GDK_IS_WINDOW (window)); + #ifdef HAVE_SHAPE_EXT if (!GDK_WINDOW_DESTROYED (window) && - gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window))) + gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window))) gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), FALSE); + GDK_WINDOW_XID (window), FALSE, ShapeBounding); #endif } @@ -5281,7 +5363,6 @@ gdk_window_set_child_shapes (GdkWindow *window) * This function is distinct from gdk_window_set_child_shapes() * because it includes @window's shape mask in the set of shapes to * be merged. - * **/ void gdk_window_merge_child_shapes (GdkWindow *window) @@ -5290,12 +5371,69 @@ gdk_window_merge_child_shapes (GdkWindow *window) #ifdef HAVE_SHAPE_EXT if (!GDK_WINDOW_DESTROYED (window) && - gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window))) + gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window))) + gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), TRUE, ShapeBounding); +#endif +} + +/** + * gdk_window_set_child_input_shapes: + * @window: a #GdkWindow + * + * Sets the input shape mask of @window to the union of input shape masks + * for all children of @window, ignoring the input shape mask of @window + * itself. Contrast with gdk_window_merge_child_input_shapes() which includes + * the input shape mask of @window in the masks to be merged. + * + * Since: 2.10 + **/ +void +gdk_window_set_child_input_shapes (GdkWindow *window) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + +#ifdef HAVE_SHAPE_EXT +#ifdef ShapeInput + if (!GDK_WINDOW_DESTROYED (window) && + gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window))) gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), TRUE); + GDK_WINDOW_XID (window), FALSE, ShapeInput); +#endif #endif } +/** + * gdk_window_merge_child_input_shapes: + * @window: a #GdkWindow + * + * Merges the input shape masks for any child windows into the + * input shape mask for @window. i.e. the union of all input masks + * for @window and its children will become the new input mask + * for @window. See gdk_window_input_shape_combine_mask(). + * + * This function is distinct from gdk_window_set_child_input_shapes() + * because it includes @window's input shape mask in the set of + * shapes to be merged. + * + * Since: 2.10 + **/ +void +gdk_window_merge_child_input_shapes (GdkWindow *window) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + +#ifdef HAVE_SHAPE_EXT +#ifdef ShapeInput + if (!GDK_WINDOW_DESTROYED (window) && + gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window))) + gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), TRUE, ShapeInput); +#endif +#endif +} + + static void gdk_window_set_static_bit_gravity (GdkWindow *window, gboolean on) { diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index 55320eb749..398c442d18 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -3970,6 +3970,7 @@ gtk_widget_set_size_request gtk_widget_set_state gtk_widget_set_style gtk_widget_shape_combine_mask +gtk_widget_input_shape_combine_mask gtk_widget_show gtk_widget_show_all gtk_widget_show_now diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 560c2696a7..187028af15 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -250,6 +250,7 @@ static GQuark quark_event_mask = 0; static GQuark quark_extension_event_mode = 0; static GQuark quark_parent_window = 0; static GQuark quark_shape_info = 0; +static GQuark quark_input_shape_info = 0; static GQuark quark_colormap = 0; static GQuark quark_pango_context = 0; static GQuark quark_rc_style = 0; @@ -324,6 +325,7 @@ gtk_widget_class_init (GtkWidgetClass *klass) quark_extension_event_mode = g_quark_from_static_string ("gtk-extension-event-mode"); quark_parent_window = g_quark_from_static_string ("gtk-parent-window"); quark_shape_info = g_quark_from_static_string ("gtk-shape-info"); + quark_input_shape_info = g_quark_from_static_string ("gtk-input-shape-info"); quark_colormap = g_quark_from_static_string ("gtk-colormap"); quark_pango_context = g_quark_from_static_string ("gtk-pango-context"); quark_rc_style = g_quark_from_static_string ("gtk-rc-style"); @@ -2352,6 +2354,13 @@ gtk_widget_realize (GtkWidget *widget) shape_info->offset_y); } + shape_info = g_object_get_qdata (G_OBJECT (widget), quark_input_shape_info); + if (shape_info) + gdk_window_input_shape_combine_mask (widget->window, + shape_info->shape_mask, + shape_info->offset_x, + shape_info->offset_y); + if (!GTK_WIDGET_NO_WINDOW (widget)) { mode = gtk_widget_get_extension_events (widget); @@ -2380,7 +2389,10 @@ gtk_widget_unrealize (GtkWidget *widget) g_return_if_fail (GTK_IS_WIDGET (widget)); if (GTK_WIDGET_HAS_SHAPE_MASK (widget)) - gtk_widget_shape_combine_mask (widget, NULL, -1, -1); + gtk_widget_shape_combine_mask (widget, NULL, 0, 0); + + if (g_object_get_qdata (G_OBJECT (widget), quark_input_shape_info)) + gtk_widget_input_shape_combine_mask (widget, NULL, 0, 0); if (GTK_WIDGET_REALIZED (widget)) { @@ -2792,8 +2804,6 @@ gtk_widget_queue_shallow_draw (GtkWidget *widget) GdkRectangle rect; GdkRegion *region; - g_return_if_fail (GTK_IS_WIDGET (widget)); - if (!GTK_WIDGET_REALIZED (widget)) return; @@ -3880,7 +3890,7 @@ static void gtk_widget_reparent_fixup_child (GtkWidget *widget, gpointer client_data) { - g_return_if_fail (client_data != NULL); + g_assert (client_data != NULL); if (GTK_WIDGET_NO_WINDOW (widget)) { @@ -4636,8 +4646,6 @@ gtk_widget_reset_rc_style (GtkWidget *widget) GtkStyle *new_style = NULL; gboolean initial_emission; - g_return_if_fail (GTK_IS_WIDGET (widget)); - initial_emission = !GTK_WIDGET_RC_STYLE (widget) && !GTK_WIDGET_USER_STYLE (widget); GTK_PRIVATE_UNSET_FLAG (widget, GTK_USER_STYLE); @@ -5766,8 +5774,6 @@ gtk_widget_set_usize_internal (GtkWidget *widget, GtkWidgetAuxInfo *aux_info; gboolean changed = FALSE; - g_return_if_fail (GTK_IS_WIDGET (widget)); - g_object_freeze_notify (G_OBJECT (widget)); aux_info = _gtk_widget_get_aux_info (widget, TRUE); @@ -5894,9 +5900,7 @@ gtk_widget_set_size_request (GtkWidget *widget, * gtk_widget_set_size_request(). To get the size a widget will * actually use, call gtk_widget_size_request() instead of * this function. - * **/ - void gtk_widget_get_size_request (GtkWidget *widget, gint *width, @@ -5930,7 +5934,6 @@ gtk_widget_get_size_request (GtkWidget *widget, * mask. This function can't be used with #GTK_NO_WINDOW widgets; * to get events on those widgets, place them inside a #GtkEventBox * and receive events on the event box. - * **/ void gtk_widget_set_events (GtkWidget *widget, @@ -6745,7 +6748,7 @@ gtk_widget_finalize (GObject *object) static void gtk_widget_real_map (GtkWidget *widget) { - g_return_if_fail (GTK_WIDGET_REALIZED (widget) == TRUE); + g_assert (GTK_WIDGET_REALIZED (widget)); if (!GTK_WIDGET_MAPPED (widget)) { @@ -6787,7 +6790,7 @@ gtk_widget_real_unmap (GtkWidget *widget) static void gtk_widget_real_realize (GtkWidget *widget) { - g_return_if_fail (GTK_WIDGET_NO_WINDOW (widget)); + g_assert (GTK_WIDGET_NO_WINDOW (widget)); GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); if (widget->parent) @@ -7046,8 +7049,8 @@ gtk_widget_shape_combine_mask (GtkWidget *widget, shape_info->offset_x = offset_x; shape_info->offset_y = offset_y; - /* set shape if widget has a gdk window allready. - * otherwise the shape is scheduled to be set by gtk_widget_realize. + /* set shape if widget has a gdk window already. + * otherwise the shape is scheduled to be set by gtk_widget_realize(). */ if (widget->window) gdk_window_shape_combine_mask (widget->window, shape_mask, @@ -7055,6 +7058,59 @@ gtk_widget_shape_combine_mask (GtkWidget *widget, } } +/** + * gtk_widget_input_shape_combine_mask: + * @widget: a #GtkWidget. + * @shape_mask: shape to be added, or %NULL to remove an existing shape. + * @offset_x: X position of shape mask with respect to @window. + * @offset_y: Y position of shape mask with respect to @window. + * + * Sets an input shape for this widget's GDK window. This allows for + * windows which react to mouse click in a nonrectangular region, see + * gdk_window_input_shape_combine_mask() for more information. + * + * Since: 2.10 + **/ +void +gtk_widget_input_shape_combine_mask (GtkWidget *widget, + GdkBitmap *shape_mask, + gint offset_x, + gint offset_y) +{ + GtkWidgetShapeInfo* shape_info; + + g_return_if_fail (GTK_IS_WIDGET (widget)); + /* set_shape doesn't work on widgets without gdk window */ + g_return_if_fail (!GTK_WIDGET_NO_WINDOW (widget)); + + if (!shape_mask) + { + if (widget->window) + gdk_window_input_shape_combine_mask (widget->window, NULL, 0, 0); + + g_object_set_qdata (G_OBJECT (widget), quark_input_shape_info, NULL); + } + else + { + shape_info = g_slice_new (GtkWidgetShapeInfo); + g_object_set_qdata_full (G_OBJECT (widget), quark_input_shape_info, + shape_info, + (GDestroyNotify) gtk_widget_shape_info_destroy); + + shape_info->shape_mask = g_object_ref (shape_mask); + shape_info->offset_x = offset_x; + shape_info->offset_y = offset_y; + + /* set shape if widget has a gdk window already. + * otherwise the shape is scheduled to be set by gtk_widget_realize(). + */ + if (widget->window) + gdk_window_input_shape_combine_mask (widget->window, shape_mask, + offset_x, offset_y); + } +} + + static void gtk_reset_shapes_recurse (GtkWidget *widget, GdkWindow *window) diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index 5dec5bdd54..d161bbebb3 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -744,6 +744,10 @@ void gtk_widget_shape_combine_mask (GtkWidget *widget, GdkBitmap *shape_mask, gint offset_x, gint offset_y); +void gtk_widget_input_shape_combine_mask (GtkWidget *widget, + GdkBitmap *shape_mask, + gint offset_x, + gint offset_y); /* internal function */ void gtk_widget_reset_shapes (GtkWidget *widget); -- 2.30.2